"""
财务数据可视化模块
基于Plotly的交互式资产负债表堆叠柱状图实现
"""

import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple
from datetime import datetime


class BalanceSheetVisualizer:
    """资产负债表可视化器"""
    
    def __init__(self):
        # 颜色编码系统
        self.color_scheme = {
            'assets': {
                'cash_equivalents': '#1f77b4',      # 深蓝 - 现金类
                'receivables': '#aec7e8',           # 浅蓝 - 应收款类
                'inventory': '#2ca02c',             # 绿色 - 存货类
                'other_current': '#98df8a',         # 浅绿 - 其他流动
                'fixed_assets': '#ff7f0e',          # 橙色 - 固定资产
                'intangible_goodwill': '#ffbb78',   # 浅橙 - 无形资产
                'long_term_investments': '#9467bd', # 紫色 - 长期投资
                'other_non_current': '#c5b0d5'      # 浅紫 - 其他非流动
            },
            'liabilities': {
                'short_term_debt': '#d62728',       # 深红 - 短期借款
                'payables': '#ff9896',              # 浅红 - 应付款类
                'advance_receipts': '#8c564b',      # 棕色 - 预收项类
                'accrued_expenses': '#c49c94',      # 浅棕 - 薪酬税费
                'long_term_debt': '#e377c2',        # 粉色 - 长期借款
                'other_current_liab': '#f7b6d3',    # 浅粉 - 其他流动负债
                'other_non_current_liab': '#7f7f7f' # 灰色 - 其他非流动负债
            },
            'equity': {
                'paid_capital': '#17becf',          # 青色 - 实收资本
                'capital_surplus': '#9edae5',       # 浅青 - 资本公积
                'retained_earnings': '#393b79',     # 深蓝紫 - 未分配利润
                'other_equity': '#637939'           # 橄榄绿 - 其他权益
            }
        }
        
        # 图表配置
        self.chart_config = {
            'height': 600,
            'margin': {'l': 80, 'r': 80, 't': 100, 'b': 120},
            'font_family': "Arial, sans-serif",
            'title_font_size': 18,
            'axis_font_size': 12
        }
    
    def create_balance_sheet_chart(self, data: pd.DataFrame, stock_info: Dict) -> go.Figure:
        """创建资产负债表堆叠柱状图"""
        
        # 数据预处理
        processed_data = self._prepare_chart_data(data)
        
        # 创建图表
        fig = go.Figure()
        
        # 添加资产部分
        self._add_assets_traces(fig, processed_data)
        
        # 添加负债部分
        self._add_liabilities_traces(fig, processed_data)
        
        # 添加权益部分
        self._add_equity_traces(fig, processed_data)
        
        # 设置布局
        self._configure_layout(fig, stock_info)
        
        # 添加交互功能
        self._add_interactivity(fig)
        
        return fig
    
    def _prepare_chart_data(self, data: pd.DataFrame) -> Dict:
        """准备图表数据"""
        # 按报告期分组并汇总各类科目
        grouped_data = {}
        
        for _, row in data.iterrows():
            report_date = row['report_date']
            category = row['category']
            value = row['account_value'] / 100000000  # 转换为亿元
            
            if report_date not in grouped_data:
                grouped_data[report_date] = {}
            
            if category not in grouped_data[report_date]:
                grouped_data[report_date][category] = 0
            
            grouped_data[report_date][category] += value
        
        # 转换为DataFrame格式
        dates = sorted(grouped_data.keys())
        chart_data = {
            'dates': dates,
            'assets': {},
            'liabilities': {},
            'equity': {}
        }
        
        # 分类汇总数据
        for date in dates:
            date_data = grouped_data[date]
            
            # 资产类
            chart_data['assets'][date] = {
                'cash_equivalents': date_data.get('cash_equivalents', 0),
                'receivables': date_data.get('receivables', 0),
                'inventory': date_data.get('inventory', 0),
                'other_current': date_data.get('other_current', 0),
                'fixed_assets': date_data.get('fixed_assets', 0),
                'intangible_goodwill': date_data.get('intangible_goodwill', 0),
                'long_term_investments': date_data.get('long_term_investments', 0),
                'other_non_current': date_data.get('other_non_current', 0)
            }
            
            # 负债类
            chart_data['liabilities'][date] = {
                'short_term_debt': date_data.get('short_term_debt', 0),
                'payables': date_data.get('payables', 0),
                'advance_receipts': date_data.get('advance_receipts', 0),
                'accrued_expenses': date_data.get('accrued_expenses', 0),
                'long_term_debt': date_data.get('long_term_debt', 0),
                'other_current_liab': date_data.get('other_current_liab', 0),
                'other_non_current_liab': date_data.get('other_non_current_liab', 0)
            }
            
            # 权益类（简化处理）
            total_assets = sum(chart_data['assets'][date].values())
            total_liabilities = sum(chart_data['liabilities'][date].values())
            total_equity = total_assets - total_liabilities
            
            chart_data['equity'][date] = {
                'paid_capital': total_equity * 0.3,      # 假设分配
                'capital_surplus': total_equity * 0.2,
                'retained_earnings': total_equity * 0.4,
                'other_equity': total_equity * 0.1
            }
        
        return chart_data
    
    def _add_assets_traces(self, fig: go.Figure, data: Dict):
        """添加资产部分的图表轨迹"""
        dates = data['dates']
        
        # 资产科目的显示顺序（从下到上）
        asset_order = [
            'cash_equivalents', 'receivables', 'inventory', 'other_current',
            'fixed_assets', 'intangible_goodwill', 'long_term_investments', 'other_non_current'
        ]
        
        # 科目中文名称映射
        asset_names = {
            'cash_equivalents': '现金及现金等价物',
            'receivables': '应收款项',
            'inventory': '存货',
            'other_current': '其他流动资产',
            'fixed_assets': '固定资产',
            'intangible_goodwill': '无形资产及商誉',
            'long_term_investments': '长期投资',
            'other_non_current': '其他非流动资产'
        }
        
        # 计算累积值（用于堆叠）
        cumulative_values = {date: 0 for date in dates}
        
        for asset_type in asset_order:
            values = [data['assets'][date][asset_type] for date in dates]
            
            # 计算当前层的底部位置
            base_values = [cumulative_values[date] for date in dates]
            
            # 更新累积值
            for i, date in enumerate(dates):
                cumulative_values[date] += values[i]
            
            # 添加轨迹
            fig.add_trace(go.Bar(
                name=asset_names[asset_type],
                x=dates,
                y=values,
                base=base_values,
                marker_color=self.color_scheme['assets'][asset_type],
                legendgroup='assets',
                legendgrouptitle_text='资产',
                hovertemplate='<b>%{fullData.name}</b><br>' +
                            '报告期: %{x}<br>' +
                            '金额: %{y:.2f}亿元<br>' +
                            '<extra></extra>'
            ))
    
    def _add_liabilities_traces(self, fig: go.Figure, data: Dict):
        """添加负债部分的图表轨迹"""
        dates = data['dates']
        
        # 负债科目的显示顺序
        liability_order = [
            'short_term_debt', 'payables', 'advance_receipts', 'accrued_expenses',
            'long_term_debt', 'other_current_liab', 'other_non_current_liab'
        ]
        
        liability_names = {
            'short_term_debt': '短期借款',
            'payables': '应付款项',
            'advance_receipts': '预收款项',
            'accrued_expenses': '应付薪酬及税费',
            'long_term_debt': '长期借款',
            'other_current_liab': '其他流动负债',
            'other_non_current_liab': '其他非流动负债'
        }
        
        # 负债以负值显示（在x轴下方）
        cumulative_values = {date: 0 for date in dates}
        
        for liability_type in liability_order:
            values = [-data['liabilities'][date][liability_type] for date in dates]
            base_values = [cumulative_values[date] for date in dates]
            
            for i, date in enumerate(dates):
                cumulative_values[date] += values[i]
            
            fig.add_trace(go.Bar(
                name=liability_names[liability_type],
                x=dates,
                y=values,
                base=base_values,
                marker_color=self.color_scheme['liabilities'][liability_type],
                legendgroup='liabilities',
                legendgrouptitle_text='负债',
                hovertemplate='<b>%{fullData.name}</b><br>' +
                            '报告期: %{x}<br>' +
                            '金额: %{y:.2f}亿元<br>' +
                            '<extra></extra>'
            ))
    
    def _add_equity_traces(self, fig: go.Figure, data: Dict):
        """添加权益部分的图表轨迹"""
        dates = data['dates']
        
        equity_order = ['paid_capital', 'capital_surplus', 'retained_earnings', 'other_equity']
        equity_names = {
            'paid_capital': '实收资本',
            'capital_surplus': '资本公积',
            'retained_earnings': '未分配利润',
            'other_equity': '其他权益'
        }
        
        # 计算负债总额（用作权益的起始位置）
        liability_totals = []
        for date in dates:
            total_liab = sum(data['liabilities'][date].values())
            liability_totals.append(-total_liab)
        
        cumulative_values = liability_totals.copy()
        
        for equity_type in equity_order:
            values = [data['equity'][date][equity_type] for date in dates]
            base_values = cumulative_values.copy()
            
            for i in range(len(dates)):
                cumulative_values[i] += values[i]
            
            fig.add_trace(go.Bar(
                name=equity_names[equity_type],
                x=dates,
                y=values,
                base=base_values,
                marker_color=self.color_scheme['equity'][equity_type],
                legendgroup='equity',
                legendgrouptitle_text='所有者权益',
                hovertemplate='<b>%{fullData.name}</b><br>' +
                            '报告期: %{x}<br>' +
                            '金额: %{y:.2f}亿元<br>' +
                            '<extra></extra>'
            ))
    
    def _configure_layout(self, fig: go.Figure, stock_info: Dict):
        """配置图表布局"""
        fig.update_layout(
            title={
                'text': f"{stock_info.get('name', '')}({stock_info.get('code', '')}) 资产负债表结构分析",
                'x': 0.5,
                'font': {'size': self.chart_config['title_font_size']}
            },
            xaxis={
                'title': '报告期',
                'tickangle': -45,
                'font': {'size': self.chart_config['axis_font_size']}
            },
            yaxis={
                'title': '金额（亿元）',
                'tickformat': '.1f',
                'font': {'size': self.chart_config['axis_font_size']},
                'zeroline': True,
                'zerolinewidth': 2,
                'zerolinecolor': 'black'
            },
            height=self.chart_config['height'],
            margin=self.chart_config['margin'],
            font={'family': self.chart_config['font_family']},
            barmode='relative',
            legend={
                'orientation': 'h',
                'y': -0.3,
                'x': 0.5,
                'xanchor': 'center',
                'groupclick': 'toggleitem'
            },
            hovermode='x unified'
        )
    
    def _add_interactivity(self, fig: go.Figure):
        """添加交互功能"""
        # 配置工具栏
        config = {
            'displayModeBar': True,
            'modeBarButtonsToAdd': [
                'downloadSVG',
                'select2d',
                'lasso2d'
            ],
            'toImageButtonOptions': {
                'format': 'png',
                'filename': 'balance_sheet_analysis',
                'height': 600,
                'width': 1000,
                'scale': 2
            },
            'displaylogo': False
        }
        
        fig.update_layout(
            updatemenus=[
                {
                    'type': 'buttons',
                    'direction': 'left',
                    'buttons': [
                        {
                            'args': [{'visible': True}],
                            'label': '显示全部',
                            'method': 'restyle'
                        },
                        {
                            'args': [{'visible': 'legendonly'}],
                            'label': '隐藏全部',
                            'method': 'restyle'
                        }
                    ],
                    'pad': {'r': 10, 't': 10},
                    'showactive': True,
                    'x': 0.01,
                    'xanchor': 'left',
                    'y': 1.02,
                    'yanchor': 'top'
                }
            ]
        )
        
        return config
    
    def create_metrics_dashboard(self, metrics: Dict, scores: Dict) -> go.Figure:
        """创建关键指标仪表板"""
        # 创建子图
        fig = make_subplots(
            rows=2, cols=2,
            subplot_titles=('综合评分', '资产质量', '财务安全', '成长性'),
            specs=[[{'type': 'indicator'}, {'type': 'indicator'}],
                   [{'type': 'indicator'}, {'type': 'indicator'}]]
        )
        
        # 综合评分
        fig.add_trace(go.Indicator(
            mode="gauge+number+delta",
            value=scores['comprehensive_score'],
            domain={'x': [0, 1], 'y': [0, 1]},
            title={'text': f"等级: {scores['grade']}"},
            gauge={
                'axis': {'range': [None, 100]},
                'bar': {'color': self._get_score_color(scores['comprehensive_score'])},
                'steps': [
                    {'range': [0, 50], 'color': "lightgray"},
                    {'range': [50, 80], 'color': "yellow"},
                    {'range': [80, 100], 'color': "lightgreen"}
                ],
                'threshold': {
                    'line': {'color': "red", 'width': 4},
                    'thickness': 0.75,
                    'value': 90
                }
            }
        ), row=1, col=1)
        
        # 其他评分指标...
        
        fig.update_layout(height=400, title_text="价值投资评分仪表板")
        
        return fig
    
    def _get_score_color(self, score: float) -> str:
        """根据评分获取颜色"""
        if score >= 80:
            return "green"
        elif score >= 60:
            return "yellow"
        else:
            return "red"


# 使用示例
if __name__ == "__main__":
    # 模拟数据
    sample_data = pd.DataFrame({
        'report_date': ['2023-12-31', '2023-09-30', '2023-06-30'],
        'category': ['cash_equivalents', 'fixed_assets', 'short_term_debt'],
        'account_value': [1000000000, 5000000000, 800000000]
    })
    
    stock_info = {'name': '平安银行', 'code': '000001'}
    
    visualizer = BalanceSheetVisualizer()
    fig = visualizer.create_balance_sheet_chart(sample_data, stock_info)
    
    # 显示图表
    fig.show()
